/* Copyright 2012 Oliver Katz

    This file is part of Theta.

    Theta is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include "core.h"

namespace api
{
	map<string, string> Plugin::parseCfg(vector<string> cfg)
	{
		map<string, string> rtn;
		for (vector<string>::iterator i = cfg.begin(); i != cfg.end(); i++)
		{
			if (i->find("=") == string::npos)
			{
				rtn[*i] = "enabled";
			}
			else
			{
				rtn[i->substr(0, i->find("="))] = i->substr(i->find("=")+1);
			}
		}
		return rtn;
	}

	Plugin::Plugin()
	{
		callback = NULL;
	}

	Plugin::Plugin(string n)
	{
		name = n;
		callback = NULL;
	}

	Plugin::Plugin(string n, vector<Frame> (*c)(Frame, vector<string>, map<string, Clause>))
	{
		name = n;
		callback = c;
	}

	string Plugin::getName()
	{
		return name;
	}

	volatile vector<Frame> Plugin::apply(Frame c, vector<string> cfg, map<string, Clause> history)
	{
		if (callback == NULL)
		{
			vector<Frame> rtn;
			rtn.push_back(c);
			return rtn;
		}
		else
			return callback(c, cfg, history);
	}

	PluginLoader::PluginLoader(string path)
	{
		handle = dlopen(path.c_str(), RTLD_LAZY);
		if (!handle)
		{
			cout << "error: cannot load plugin: " << path << "\n";
			_exit(1);
		}

		callback = (vector<Frame>(*)(Frame, vector<string>, map<string, Clause>))dlsym(handle, "callback");
		char *e = dlerror();
		if (e != NULL)
		{
			cout << "error: cannot load callback: " << e << "\n";
			_exit(1);
		}

		name = path.substr(string("libthetaplugin_").size());
		name = name.substr(0, name.find("."));
	}

	PluginLoader::~PluginLoader()
	{
		dlclose(handle);
	}

	Plugin PluginLoader::load()
	{
		return Plugin(name, callback);
	}

	PluginDB::PluginDB()
	{
	}

	void PluginDB::use(Plugin p)
	{
		plugins.push_back(p);
	}

	void PluginDB::loadPluginsFrom(string path)
	{
		DIR *d = opendir(path.c_str());
		struct dirent *dir;

		if (!d)
		{
			cout << "error: cannot open plugin directory\n";
			_exit(1);
		}

		while ((dir = readdir(d)) != NULL)
		{
			string f(dir->d_name);
			if (f.find(".so.") != string::npos && f.find("libthetaplugin_") != string::npos)
			{
				PluginLoader pl = PluginLoader(path+"/"+f);
				plugins.push_back(pl.load());
			}
		}

		closedir(d);
	}
}